﻿using AdminManager.Permissions;
using AdminManager.System.RoleNavigations;
using AdminManager.Tools;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

namespace AdminManager.System
{
    [Authorize(IdentityPermissions.Roles.Default)]
    public class RoleNavigationsAppService : ApplicationService, IRoleNavigationsAppService
    {
        private readonly IRepository<Navigations> _navigationsRepository;
        private readonly IRepository<RoleNavigation> _roleNavigationRepository;
        private readonly IdentityRoleManager _identityRoleManager;
        public RoleNavigationsAppService(IRepository<Navigations> navigationsRepository,
            IRepository<RoleNavigation> roleNavigationRepository,
            IdentityRoleManager identityRoleManager) 
        {
            this._navigationsRepository = navigationsRepository;
            this._roleNavigationRepository = roleNavigationRepository;
            this._identityRoleManager = identityRoleManager;
        }
        public async Task<List<RoleNavigationsItemDto>> GetAsync([NotNull] string roleId)
        {
            var nav_list = (await this._navigationsRepository.GetQueryableAsync()).AsNoTracking().ToList();
            var role_nav_list = (await this._roleNavigationRepository.GetQueryableAsync()).AsNoTracking()
                .Where(p=>p.RoleId==Guid.Parse(roleId)).ToList();
            var action_list = EnumsHelper.GetEnumList<ManagerActionEnums>();
            var adminRoleInfo = await this._identityRoleManager.FindByNameAsync(AdminManagerConsts.AdminRoleName);
            List<RoleNavigationsItemDto> roleNavigationsList = new List<RoleNavigationsItemDto>();
            foreach (var item in nav_list)
            {
                RoleNavigationsItemDto iteminfo = new RoleNavigationsItemDto();
                iteminfo.Name = item.Name;
                iteminfo.NavigatioinId = item.Id;
                iteminfo.ParentId = item.ParentId;
                iteminfo.IsSelected = role_nav_list.Exists(p=>p.NavigationId == item.Id);
                
                if (!string.IsNullOrWhiteSpace(item.Actions))
                {
                    string[] temp_action = item.Actions.Split(",");
                    List<RoleNavigationsItemActionsDto> roleNavigationsItemActionsDtosList = new List<RoleNavigationsItemActionsDto>();
                    List<string> temp_select = new List<string>();
                    RoleNavigation currentRoleNavigation = role_nav_list.FirstOrDefault(p => p.NavigationId == item.Id);
                    foreach (var action in temp_action)
                    {
                        RoleNavigationsItemActionsDto roleNavigationsItemActionsDto = new RoleNavigationsItemActionsDto();
                        roleNavigationsItemActionsDto.IsSelected = currentRoleNavigation==null?false: currentRoleNavigation.Actions.Contains(action);
                        if (roleNavigationsItemActionsDto.IsSelected) 
                        {
                            temp_select.Add(action);

                        }
                        roleNavigationsItemActionsDto.ActionsName = action;
                        roleNavigationsItemActionsDto.Key = String.Format("{0}_{1}", item.Id, action);
                        roleNavigationsItemActionsDto.DisplayName = action_list.FirstOrDefault(p => p.Name == action)?.DisplayName??action;
                        roleNavigationsItemActionsDtosList.Add(roleNavigationsItemActionsDto);
                    }
                    iteminfo.Actions = roleNavigationsItemActionsDtosList;
                    iteminfo.SelectActions = temp_select.ToArray();
                }
                if (adminRoleInfo.Id == Guid.Parse(roleId))
                {
                    iteminfo.IsSelected = true;
                    iteminfo.SelectActions = action_list.Select(p=>p.Name).ToArray();
                }
                roleNavigationsList.Add(iteminfo);
            }
            return roleNavigationsList;
        }
        [Authorize(IdentityPermissions.Roles.ManagePermissions)]
        public async Task UpdateAsync([NotNull] string id, UpdateRoleNavigationDto input)
        {
            List<RoleNavigation> items =  await this._roleNavigationRepository.GetListAsync(p => p.RoleId == Guid.Parse(id));
            if (items.Count>0)
            {
                await this._roleNavigationRepository.DeleteManyAsync(items);
            } 
            if (input.Items.Count()==0)
            {
                return;
            }
            List<RoleNavigation> addList = new List<RoleNavigation>();
            foreach (var item in input.Items)
            {
                RoleNavigation roleNav = new RoleNavigation
                {
                    NavigationId = Guid.Parse(item.NavigationId),
                    RoleId = Guid.Parse(id),
                    Actions = item.Actions.JoinAsString(",")
                };
                addList.Add(roleNav);
            }
            await this._roleNavigationRepository.InsertManyAsync(addList);
        }
        public async Task<List<MenuDto>> GetMenusAsync()
        {
            List<Navigations> navigationsList = (await this._navigationsRepository.GetQueryableAsync()).AsNoTracking().ToList();

            List<MenuDto> menusList = new List<MenuDto>();

            IEnumerable<Navigations> selectNavList = null;
            if (CurrentUser.Roles.Contains(AdminManagerConsts.Administrator))
            {
                selectNavList = navigationsList;
            }
            else
            {
                List<IdentityRole> identityRoleList = new List<IdentityRole>();
                foreach (var item in CurrentUser.Roles)
                {
                    identityRoleList.Add(await this._identityRoleManager.FindByNameAsync(item));
                }
                Guid[] roleIdArray = identityRoleList.Select(p => p.Id).ToArray();
                var groupNavigationIdArray = (await this._roleNavigationRepository.GetQueryableAsync()).AsNoTracking()
               .Where(p => roleIdArray.Contains(p.RoleId))
               .Where(p => p.Actions.Contains(ManagerActionEnums.Show.ToString()))
               .GroupBy(p => p.NavigationId)
               .Select(p => p.Key).ToList();


                selectNavList = navigationsList.Where(p => groupNavigationIdArray.Contains(p.Id));

            }
            selectNavList = selectNavList.OrderByDescending(p => p.Sort);
            foreach (var item in selectNavList)
            {
                MenuDto menuDto = new MenuDto();
                menuDto.Name = item.RouterName;
                menuDto.Meta = new MenuMeta
                {
                    Icon = item.Icon,
                    Title = item.Name
                };
                menuDto.Component = item.ComponentPath;
                menuDto.Path = item.RouterPath;
                menuDto.Id = item.Id.ToString();
                menuDto.ParentId = item.ParentId;
                menuDto.Redirect = item.Redirect;
                menusList.Add(menuDto);
            }
            return menusList;
        }

        public async Task<List<string>> GetMenusActionCodeAsync()
        {
            List<Navigations> navigationsList = (await this._navigationsRepository.GetQueryableAsync()).AsNoTracking().ToList();

            List<string> menusList = new List<string>();

            IEnumerable<Navigations> selectNavList = null;
            if (CurrentUser.Roles.Contains(AdminManagerConsts.Administrator))
            {
                var action_list = EnumsHelper.GetEnumList<ManagerActionEnums>();
                selectNavList = navigationsList;
                foreach (var item in selectNavList)
                {
                    foreach (var action_item in action_list)
                    {
                        var key = string.Format("{0}_{1}", item.RouterName, action_item);
                        if (!menusList.Contains(key))
                        {
                            menusList.Add(key);
                        }
                    }
                }
            }
            else
            {
                List<IdentityRole> identityRoleList = new List<IdentityRole>();
                foreach (var item in CurrentUser.Roles)
                {
                    identityRoleList.Add(await this._identityRoleManager.FindByNameAsync(item));
                }
                Guid[] roleIdArray = identityRoleList.Select(p => p.Id).ToArray();
                var roleNavigationArray = (await this._roleNavigationRepository.GetQueryableAsync()).AsNoTracking()
               .Where(p => roleIdArray.Contains(p.RoleId)).ToList(); 
                foreach (var item in roleNavigationArray)
                {
                    if (!item.Actions.IsNullOrWhiteSpace())
                    {
                        var navItem = navigationsList.FirstOrDefault(p => p.Id == item.NavigationId);
                        var actionList = item.Actions.Split(",");
                        foreach (var action_item in actionList)
                        {
                            var key = string.Format("{0}_{1}", navItem.RouterName, action_item);
                            if (!menusList.Contains(key))
                            {
                                menusList.Add(key);
                            }
                            
                        }
                    }
                    
                }

            }
           
            return menusList;

        }
    }
}
